package algoritmo;

import java.util.Random;

public class CromosomaFuncionCinco extends Cromosoma{

		// extremos del intervalo considerado
		// para los valores del dominio
		float[]	min;//Debe ser un array por si hay varias variables
		float[]	max;
		int numGenes;
		int[] longitudCadaGen;
		int numVariables;
		float tol;
		int longitudCromosoma;
		float maximo;
		float aptitudRetocada;
		
		public void pinta() {
			System.out.println("APTITUD: "+ aptitud);
			for(int i=0;i<numGenes;i++)
				System.out.println("FENOTIPO X" + i + " " + fenotipo[i]);
			String g="";
			int suma=0;
			int suma1=0;
			for (int i=0;i<numGenes;i++){
				for(int j=suma;j<longitudCadaGen[i]+suma1;j++){
					if(genes[j])
						g = g + '1';
					else
						g = g + '0';
				}
				g = g + " ";
				suma = longitudCadaGen[i];
				if(i<numGenes-1)
					suma1 = longitudCadaGen[i+1];
			}
			System.out.println(g+"\n");
			
		}

		
		public CromosomaFuncionCinco(){
			
		}
		
		public void inicializaCromosoma(float[] min, float[] max, int numGenes, int numVariables,float tol) {
			this.max = new float[numGenes];
			this.min = new float[numGenes];
			
			for(int i=0;i<numGenes;i++){
				this.min[i] = min[i];
				this.max[i] = max[i];
			}
			
			this.tol = tol;
			this.numGenes = numGenes;
			
			longitudCadaGen = new int[numGenes];
			longitudCromosoma = calculaLongitud();/*se calcula con min y max de cada variable: x,y,z...*/
			this.numVariables = numVariables;
			
			
			genes = new boolean[longitudCromosoma];	
			Random r = new Random();
			for(int i=0;i<longitudCromosoma;i++){
				if( r.nextDouble() < 0.5)
					genes[i] = true;
				else
					genes[i] = false;
			}
			
			fenotipo = new float[numGenes];
			fenotipo = fenotipo();
			aptitud = evalua();
		}
		
		public void inicializaParcialCromosoma(float[] min, float[] max,int numGenes, int numVariables,float tol) {
			this.min = new float[numGenes];
			this.max = new float[numGenes];
			longitudCadaGen = new int[numGenes];
			
			for(int i=0;i<numGenes;i++){
				this.min[i] = min[i];
				this.max[i] = max[i];
			}
			
			this.numGenes = numGenes;
			this.numVariables = numVariables;
			this.tol = tol;
			
			longitudCromosoma = calculaLongitud();
			genes = new boolean[longitudCromosoma];	
			fenotipo = new float[numGenes];
			
		}

		public int calculaLongitud() {
			float aux = 0;
			int resul = 0;
			for(int i=0;i<numGenes;i++){
				aux = (float) (Math.log(1+((max[i]-min[i])/tol))/Math.log(2));
				longitudCadaGen[i] = (int) Math.ceil(aux);//Redondeas hacia arriba siempre si hay decimales
				resul = resul + longitudCadaGen[i];
			}
			
			return resul;
		}
			
		public int[] binomio(){//el valor del individuo
			int exponente;
			int[] resul = new int [numGenes];
			int suma = 0;
			int suma1 = longitudCadaGen[numGenes-1];
			
			for(int j=numGenes-1;j>=0;j--){
				exponente = 0;
				for( int i=longitudCromosoma-1-suma; i>(longitudCromosoma-suma1-1); i--){
					if( genes[i] == true )
						resul[j]  = (int) (resul[j] + Math.pow(2,exponente));
					exponente++;
				}
				if(j>0){//Para que suma1 no se salga del rango en cuando j=0(ultima iteracion)
					suma = suma + longitudCadaGen[j];
					suma1 = suma1 + longitudCadaGen[j-1];
				}
			}
			
//			for(int j=numGenes-1;j>=0;j--){
//				for(int i=longitudCromosoma-1;i>=longitudCadaGen[0];i--){
//					if( genes[i] == true )
//						resul[1]  = (int) (resul[1] + Math.pow(2,exponente));
//					exponente++;
//				}
//				exponente = 0;
//				for(int i=longitudCadaGen[0]-1;i>=0;i--){
//					if( genes[i] == true )
//						resul[0]  = (int) (resul[0] + Math.pow(2,exponente));
//					exponente++;
//				}
//			}
			return resul;
		}
		
		public float[] fenotipo(){
			float[] resul = new float[numGenes];
			int[] binomio = binomio();
			for(int i=0;i<binomio.length;i++){
				float aux = (float)binomio[i];
				resul[i]= (float) (min[i] + aux * ( (max[i]-min[i])/(Math.pow(2, longitudCadaGen[i]) - 1) ) );
			}			
			return resul;			 
		}
		
		
		public float evalua() { 
			
			float[] fenAux = fenotipo();
			float a,b,sumatorio1 = 0,sumatorio2 = 0,resul = 0;
			for(int i=1;i<=5;i++){
				a = (float) (i * Math.cos( (i+1)*fenAux[0]+i ));
				sumatorio1 = sumatorio1 + a;
			}
			for(int i=1;i<=5;i++){
				a = (float) (i * Math.cos( (i+1)*fenAux[1]+i ));
				sumatorio2 = sumatorio2 + a;
			}
			resul = sumatorio1 * sumatorio2;
			
			return resul;
		}
		
//		public float evalua() { 
//			float[]x = fenotipo();
//			float numerador = (float) Math.sin(x[0]);
//			float denominador = (float) (1 + (Math.sqrt(x[0])) + (Math.cos(x[0])/(1+x[0])));
//			return numerador / denominador;
//		}
		
		
		public void copia(Cromosoma nuevo) {
			((CromosomaFuncionCinco)nuevo).numGenes = this.numGenes;
			((CromosomaFuncionCinco)nuevo).numVariables = this.numVariables;
			((CromosomaFuncionCinco)nuevo).tol = this.tol;
			((CromosomaFuncionCinco)nuevo).longitudCromosoma = this.longitudCromosoma;
			
			nuevo.setAptitud(this.aptitud);
//			if(nuevo.fenotipo==0 || nuevo.aptitud==0)
//				System.out.println("Cero");
			nuevo.setPuntuacion(this.puntuacion);
			nuevo.setPuntuacionAcumulada(this.punt_acum);
			
			nuevo.genes = new boolean[longitudCromosoma];
			for(int i=0;i<longitudCromosoma;i++){
				nuevo.setGen(i, this.genes[i]);
			}
			
			((CromosomaFuncionCinco)nuevo).min = new float[min.length];
			for(int i=0;i<min.length;i++){
				((CromosomaFuncionCinco)nuevo).setMin(i, this.min[i]);
			}
			
			((CromosomaFuncionCinco)nuevo).max = new float[max.length];
			for(int i=0;i<max.length;i++){
				((CromosomaFuncionCinco)nuevo).setMax(i, this.max[i]);
			}
			
			((CromosomaFuncionCinco)nuevo).longitudCadaGen = new int[longitudCadaGen.length];//O numGenes
			for(int i=0;i<longitudCadaGen.length;i++){
				((CromosomaFuncionCinco)nuevo).setLongCadaGen(i, this.longitudCadaGen[i]);
			}
			
			((CromosomaFuncionCinco)nuevo).fenotipo = new float[numGenes];
			for(int i=0;i<numGenes;i++){
				((CromosomaFuncionCinco)nuevo).setFenotipo(i, this.fenotipo[i]);
			}
			
			
		}
		
		private void setFenotipo(int i, float valor) {
			fenotipo[i] = valor;
			
		}


		private void setLongCadaGen(int i, int valor) {
			longitudCadaGen[i] = valor;
			
		}


		private void setMin(int i, float valor) {
			min[i] = valor;
			
		}
		
		private void setMax(int i, float valor) {
			max[i] = valor;
			
		}


		public int getLongitudCromosoma(){
			return longitudCromosoma;
		}

		
		public float getMin(int i){
			return min[i];
		}
		
		public float getMax(int i){
			return max[i];
		}

		public int getNumGenes() {
			return numGenes;
		}

		public int getNumVariables() {
			return numVariables;
		}

		public float getMax(){
			return maximo;
		}

		public void setAptitudMaxima(float max) {
			maximo = max;
			
		}
		
		public float getAptitudRetocada() {
			return aptitudRetocada;
		}

		public void setAptitudRetocada(float aptitudRetocada) {
			this.aptitudRetocada = aptitudRetocada;
		}
}